use std::{
    path::Path,
    sync::{
        atomic::{Ordering, AtomicU16},
        Arc,
    },
    time::Duration,
};

use owo_colors::OwoColorize;
use pbr::ProgressBar;
use tokio::{sync::mpsc::channel, task::JoinHandle};

use crate::ts::download_ts;

pub mod m3u8_env;
pub mod m3u8_key;
pub mod m3u8_parser;
pub mod ts;
pub mod utils;

/// 下载m3u8视频
pub async fn m3u8_dl(
    ts_dir: &Path,
    ts_url_list: Vec<(u32, String)>,
    key: m3u8_key::Key,
    buff_size: usize,
) -> Result<(), String> {
    let (tx, mut rx) = channel::<_>(buff_size);

    let key = Arc::new(key);

    // 计数器
    let counter = Arc::new(AtomicU16::new(0));

    let _counter = counter.clone();
    tokio::spawn(async move {
        for (index, url) in ts_url_list {
            // 如果计数器的值大于等于最多并发数 ， 进入Pending状态
            while _counter.load(Ordering::SeqCst) >= buff_size as u16 {
                tokio::time::sleep(Duration::from_micros(20_u64)).await;
            }

            tx.send((index, url.clone())).await.unwrap();

            // 任务发送到队列后，计数器需要+1
            _counter.fetch_add(1, Ordering::SeqCst);
        }
    });

    let mut handle_list = Vec::<JoinHandle<()>>::new();
    while let Some((index, url)) = rx.recv().await {
        let _counter = counter.clone();
        let _ts_dir = ts_dir.to_path_buf();
        let _key = key.clone();

        let handle = tokio::spawn(async move {
            if let Err(_err) = download_ts(&_ts_dir, &url, index as usize, _key).await {
                eprintln!("Err: {_err}");
            }

            // 任务处理完毕，计数器-1
            _counter.fetch_sub(1, Ordering::SeqCst);
        });

        handle_list.push(handle);
    }

    // 等待所有Task执行完毕
    let mut pb = ProgressBar::new(handle_list.len() as u64);
    pb.format("[>>=]");

    for handle in handle_list {
        handle.await.unwrap();
        pb.inc();
    }
    pb.finish_print("done");
    println!("{}", "TS下载完成".green());

    Ok(())
}
